package com.matrix.async.core;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.format.annotation.DateTimeFormat;

import com.matrix.async.bean.AsyncTaskBean;
import com.matrix.async.service.AsyncTaskService;
import com.matrix.core.anotations.Extend;

/**
 * 
 * @author JIANGYOUYAO
 * @email 935090232@qq.com
 * @date 2017年9月4日
 */
public class AsyncTask implements Serializable, Task {

	/**
	 * 0：待处理
	 */
	public final static String TASK_WAIT = "0";

	/**
	 * 1： 处理中
	 */
	public final static String TASK_HANDING = "1";

	/**
	 * 2:执行成功
	 */
	public final static String TASK_SUCCESS = "2";
	/**
	 * 3:执行失败
	 */
	public final static String TASK_FAIL = "3";

	/**
	 * 4:执行时异常
	 */
	public final static String TASK_EXCEPTION = "4";

	Logger log = Logger.getLogger(AsyncTask.class);
	private static final long serialVersionUID = 6837212090079917889L;

	// 序列化忽略这个属性
	private transient AsyncTaskService asyncTaskService;

	private final TaskHandler handler;

	private final Map<String, String> dataMap;

	private final String id;
	private final String name;
	private final String taskType;
	private String processedBy = null;
	private final Date initTime = new Date();
	private Date enqueueTime = null;
	private Date dequeueTime = null;
	private Date startTime = null;
	private Date finishTime = null;


	private RetryPolicy retryPolicy = new Retry3Times();

	/**
	 * 
	 * @author JIANGYOUYAO
	 * @email 935090232@qq.com
	 * @date 2017年9月4日
	 * @param id
	 * @param taskType
	 * @param asyncTaskService
	 * @param dataMap
	 * @param handler
	 */
	public AsyncTask(String id, String taskType, AsyncTaskService asyncTaskService, Map<String, String> dataMap,
			TaskHandler handler) {
		this.handler = handler;
		this.dataMap = dataMap;
		this.name = "Task[" + taskType + "]";
		this.id = id;
		this.taskType = taskType;
		this.asyncTaskService = asyncTaskService;
	}

	@Override
	public String toString() {
		// return "AsyncTask [id=" + id + ", processedBy=" + processedBy + ",
		// name=" + name + ", taskType=" + taskType
		// + ", initTime=" + initTime + ", enqueueTime=" + enqueueTime + ",
		// dequeueTime=" + dequeueTime
		// + ", startTime=" + startTime + ", finishTime=" + finishTime + ",
		// dataMap=" + dataMap + "]";
		return "AsyncTask [id=" + id + "]";
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public String getTaskType() {
		return taskType;
	}

	@Override
	public void enqueue(QueueEvnet e) {
		this.enqueueTime = new Date();
		// log.info("任务被加入队列" +this.toString());
	}

	@Override
	public void dequeue(QueueEvnet e) {
		this.dequeueTime = new Date();
		// log.info("任务出栈啦==" + this.toString());

	}

	@Override
	public void lackOfTask(QueueEvnet e) {
	}

	@Override
	public void fullOfTask(QueueEvnet e) {
	}

	@Override
	public String getID() {
		return id;
	}

	@Override
	public void beforeExecute() {
		this.startTime = new Date();
		try {
			this.processedBy = InetAddress.getLocalHost().getHostName();
			log.info("任务执行之前" + this.toString());
		} catch (UnknownHostException e) {
			log.error(e.toString());
		}

	}

	@Override
	public boolean execute() {

		return this.handler.execute(dataMap);
	}

	@Override
	public void afterExecute() {
		this.finishTime = new Date();
		updateTaskStatus(id, TASK_SUCCESS, null);
		log.info("任务执行之后" + this.toString());
	}

	/**
	 * 执行后更新任务状态
	 * 
	 * @param taskId
	 * @param status
	 * @param errorLog
	 */
	private void updateTaskStatus(String taskId, String status, String errorLog) {
		asyncTaskService.updateTaskInfo(getAsyncTaskBean(taskId, status, errorLog));
	}

	/**
	 * 构造更新任务需要的参数
	 * 
	 * @param taskId
	 * @param status
	 * @param errorLog
	 * @return
	 */
	private AsyncTaskBean getAsyncTaskBean(String taskId, String status, String errorLog) {
		AsyncTaskBean taskBean = new AsyncTaskBean();
		taskBean.setId(taskId);
		taskBean.setStatus(status);
		taskBean.setProcessedBy(processedBy);
		taskBean.setInitTime(initTime);
		taskBean.setEnqueueTime(enqueueTime);
		taskBean.setDequeueTime(dequeueTime);
		taskBean.setStartTime(startTime);
		taskBean.setFinishTime(finishTime);
		taskBean.setErrorLog(errorLog);
		return taskBean;
	}

	@Override
	public boolean retry() {
		updateTaskStatus(id, TASK_FAIL, null);
		if (retryPolicy.isRetry()) {
			return true;
		}
		return false;
	}

	@Override
	public void onError(Exception e) {
		this.finishTime = new Date();
		this.handler.onError(dataMap, e);
		updateTaskStatus(id, TASK_EXCEPTION, ExceptionUtils.getStackTraceMessage(e));

	}

	@Override
	public void setRetryPolicy(RetryPolicy retryPolicy) {
		this.retryPolicy = retryPolicy;
	}

	public Logger getLog() {
		return log;
	}

	public void setLog(Logger log) {
		this.log = log;
	}

	public String getProcessedBy() {
		return processedBy;
	}

	public void setProcessedBy(String processedBy) {
		this.processedBy = processedBy;
	}

	public Date getEnqueueTime() {
		return enqueueTime;
	}

	public void setEnqueueTime(Date enqueueTime) {
		this.enqueueTime = enqueueTime;
	}

	public Date getDequeueTime() {
		return dequeueTime;
	}

	public void setDequeueTime(Date dequeueTime) {
		this.dequeueTime = dequeueTime;
	}

	public Date getStartTime() {
		return startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public Date getFinishTime() {
		return finishTime;
	}

	public void setFinishTime(Date finishTime) {
		this.finishTime = finishTime;
	}


	public TaskHandler getHandler() {
		return handler;
	}

	public Map<String, String> getDataMap() {
		return dataMap;
	}

	public String getId() {
		return id;
	}

	public Date getInitTime() {
		return initTime;
	}

	public RetryPolicy getRetryPolicy() {
		return retryPolicy;
	}
 

	
}
